package com.xjk.ftp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 鉴于原FtpClientUtil中使用的是sun.net.ftp.FTPClient(经常会出现莫名其妙的问题，极其不建议使用) 将其改为org.apache.commons.net.ftp.FTPClient
 */
public class FtpClientUtil{

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    FTPClient ftpClient;

    private String server;

    private int port;

    private String userName;

    private String userPassword;

    public FtpClientUtil(String server, int port, String userName, String userPassword){
        this.server = server;
        this.port = port;
        this.userName = userName;
        this.userPassword = userPassword;
        open();
    }

    /**
     * 链接到服务器
     */
    public boolean open(){
        boolean result = true;
        if (ftpClient == null || !ftpClient.isConnected()){
            try{
                ftpClient = new FTPClient();
                ftpClient.connect(server, port);
                ftpClient.login(userName, userPassword);
                logger.info("##### connect ftp success! host:[{}],port:[{}]", new Object[] { server, port });
                // 告诉服务器需要开一个端口用来传输数据，由于安全限制，有可能某些端口被阻止了，就会出现阻塞，代码一直卡在那里不执行
                ftpClient.enterLocalPassiveMode();
            }catch (Exception e){
                e.printStackTrace();
                ftpClient = null;
                result = false;
                logger.error("##### ERROR!!! connect ftp fail! host:[{}],port:[{}],message:[{}]", new Object[] { server, port, e.getMessage() });
            }
        }
        return result;
    }

    /**
     * 上传文件到FTP服务器
     */
    public boolean upload(String localDirectoryAndFileName,String ftpDirectory) throws Exception{
        File src = new File(localDirectoryAndFileName);
        try{
            ftpDirectory = ftpDirectory + src.getName() + "/";
            this.ftpClient.makeDirectory(ftpDirectory);
            // ftpClient.listDirectories();
        }catch (IOException e){
            e.printStackTrace();
            logger.info(ftpDirectory + "目录创建失败");
        }
        File[] allFile = src.listFiles();
        for (int currentFile = 0; currentFile < allFile.length; currentFile++){
            if (!allFile[currentFile].isDirectory()){
                String srcName = allFile[currentFile].getPath().toString();
                uploadFile(new File(srcName), ftpDirectory);
            }else{
                // 递归上传子目录文件
                upload(allFile[currentFile].getPath().toString(), ftpDirectory);
            }
        }
        return true;
    }

    /**
     * 从FTP服务器上下载文件并返回下载文件长度
     */
    public boolean download(String ftpDirectoryAndFileName,String localDirectoryAndFileName) throws Exception{
        try{
            String fileName = new File(ftpDirectoryAndFileName).getName();
            localDirectoryAndFileName = localDirectoryAndFileName + fileName + "//";
            new File(localDirectoryAndFileName).mkdirs();
            FTPFile[] allFile = this.ftpClient.listFiles(ftpDirectoryAndFileName);
            for (int currentFile = 0; currentFile < allFile.length; currentFile++){
                if (!allFile[currentFile].isDirectory()){
                    downloadFile(allFile[currentFile].getName(), localDirectoryAndFileName, ftpDirectoryAndFileName);
                }
            }
            for (int currentFile = 0; currentFile < allFile.length; currentFile++){
                if (allFile[currentFile].isDirectory()){
                    String strremoteDirectoryPath = ftpDirectoryAndFileName + "/" + allFile[currentFile].getName();
                    downLoadDirectory(localDirectoryAndFileName, strremoteDirectoryPath);
                }
            }
        }catch (IOException e){
            e.printStackTrace();
            logger.info("下载文件夹失败");
            return false;
        }
        return true;
    }

    /***
     * 下载文件夹
     */
    public boolean downLoadDirectory(String localDirectoryPath,String remoteDirectory){
        try{
            String fileName = new File(remoteDirectory).getName();
            localDirectoryPath = localDirectoryPath + fileName + "//";
            new File(localDirectoryPath).mkdirs();
            FTPFile[] allFile = this.ftpClient.listFiles(remoteDirectory);
            for (int currentFile = 0; currentFile < allFile.length; currentFile++){
                if (!allFile[currentFile].isDirectory()){
                    downloadFile(allFile[currentFile].getName(), localDirectoryPath, remoteDirectory);
                }else{
                    String strremoteDirectoryPath = remoteDirectory + "/" + allFile[currentFile].getName();
                    downLoadDirectory(localDirectoryPath, strremoteDirectoryPath);
                }
            }
        }catch (IOException e){
            e.printStackTrace();
            logger.info("下载文件夹失败");
            return false;
        }
        return true;
    }

    /***
     * 下载文件
     * 
     * @param remoteFileName
     *            待下载文件名称
     * @param localDires
     *            下载到当地那个路径下
     * @param remoteDownLoadPath
     *            remoteFileName所在的路径
     */

    public boolean downloadFile(String remoteFileName,String localDires,String remoteDownLoadPath){
        String strFilePath = localDires + remoteFileName;
        BufferedOutputStream outStream = null;
        boolean success = false;
        try{
            this.ftpClient.changeWorkingDirectory(remoteDownLoadPath);
            outStream = new BufferedOutputStream(new FileOutputStream(strFilePath));
            logger.info(remoteFileName + "开始下载....");
            success = this.ftpClient.retrieveFile(remoteFileName, outStream);
            if (success){
                logger.info(remoteFileName + "成功下载到" + strFilePath);
                return success;
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error(remoteFileName + "下载失败");
        }finally{
            if (null != outStream){
                try{
                    outStream.flush();
                    outStream.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        if (!success){
            logger.error(remoteFileName + "下载失败!!!");
        }
        return success;
    }

    public InputStream getInputStream(String path,String fileName){
        InputStream inputStream = null;
        try{
            // 创建目录（如果目录已经存在，则不会再创建，并返回false）
            ftpClient.makeDirectory(path);
            // 跳到该目录下
            ftpClient.changeWorkingDirectory(path);
            path = path.endsWith("/") ? path : path + "/";
            inputStream = ftpClient.retrieveFileStream(path + fileName);
        }catch (IOException e){
            e.printStackTrace();
        }
        return inputStream;
    }

    /**
     * 返回FTP目录下的文件列表
     */
    public List<String> getFileNameList(String ftpDirectory){
        List<String> list = new ArrayList<String>();
      if (!open()) {
        return list;
      }
        try{
            FTPFile[] ftpFileArray = ftpClient.listFiles(ftpDirectory);
            if (ftpFileArray != null && ftpFileArray.length > 0){
                for (FTPFile ftpFile : ftpFileArray){
                    list.add(ftpFile.getName());
                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 删除FTP上的文件
     */
    public boolean deleteFile(String ftpDirAndFileName){
        boolean result = true;
        if (!open()){
            result = false;
        }else{
            try{
                ftpClient.deleteFile(ftpDirAndFileName);
            }catch (IOException e){
                logger.error("###ERROR! delete ftp file fail,PATH:[{}]", new Object[] { ftpDirAndFileName });
                result = false;
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 上传
     */
    public int upload(String toPath,InputStream is,String fileName){
        int result = 0;
        try{
            // 目录
            toPath = toPath.endsWith("/") ? toPath : toPath + "/";
            // 创建目录
            if (ftpClient.makeDirectory(toPath)){
                // 改变工作目录
                if (ftpClient.changeWorkingDirectory(toPath)){
                    // 生成文件
                    if (ftpClient.storeFile(toPath + fileName, is)){
                        // 结果为成功
                        result = 1;
                    }
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }

        return result;
    }

    /***
     * 上传Ftp文件
     */
    public boolean uploadFile(File localFile,String romotUpLoadePath){
        BufferedInputStream inStream = null;
        boolean success = false;
        try{
            this.ftpClient.changeWorkingDirectory(romotUpLoadePath);// 改变工作路径
            inStream = new BufferedInputStream(new FileInputStream(localFile));
            logger.info(localFile.getName() + "开始上传.....");
            success = this.ftpClient.storeFile(localFile.getName(), inStream);
            if (success == true){
                logger.info(localFile.getName() + "上传成功");
                return success;
            }
        }catch (FileNotFoundException e){
            e.printStackTrace();
            logger.error(localFile + "未找到");
        }catch (IOException e){
            e.printStackTrace();
        }finally{
            if (inStream != null){
                try{
                    inStream.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return success;
    }

    /**
     * 删除FTP目录
     */
    public boolean deleteDirectory(String ftpDirectory){
        boolean result = true;
        if (!open()){
            result = false;
        }else{
            try{
                ftpClient.removeDirectory(ftpDirectory);
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 关闭链接
     */
    public void close(){
        if (ftpClient != null && ftpClient.isConnected()){
            try{
                ftpClient.disconnect();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args){
        try{
            String server = "10.8.12.133";
            FtpClientUtil client = new FtpClientUtil(server, 22, "crmuser", "root1234");
            String ftpDirectoryAndFileName = "apple_test/1.txt";
            String localDirectoryAndFileName = "F:/d";
            client.download(ftpDirectoryAndFileName, localDirectoryAndFileName);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 将文件转移到另一个目录
     */
    public void moveFile(String filename,String from,String to){
        try{
            ftpClient.mkd(to);
            from = from.endsWith("/") ? from : from + "/";
            to = to.endsWith("/") ? to : to + "/";
            ftpClient.rename(from + filename, to + filename);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    /**
     * 删除某个文件
     */
    public void delete(String fromPath,String fileName){
        try{
            fromPath = fromPath.endsWith("/") ? fromPath : fromPath + "/";
            ftpClient.deleteFile(fromPath + fileName);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

}
